//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "BasicType.h"
#include "string.h"
#include "Time.h"
#include "SerialPortThread.h"
#include "Pass.h"
#include "ChangePass.h"
#include "Main.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "frxClass"
#pragma link "frxExportPDF"
#pragma link "frxExportRTF"
#pragma link "frxExportXLS"
#pragma link "frxExportXML"
#pragma link "frxCross"
#pragma link "frxDBSet"
#pragma link "frxClass"
#pragma link "frxCross"
#pragma link "frxDBSet"
#pragma link "frxExportPDF"
#pragma link "frxExportRTF"
#pragma link "frxExportXLS"
#pragma link "frxExportXML"
#pragma link "frxClass"
#pragma link "frxDBSet"
#pragma link "frxExportPDF"
#pragma link "frxExportRTF"
#pragma link "frxExportXLS"
#pragma link "frxClass"
#pragma link "frxDBSet"
#pragma link "frxExportPDF"
#pragma link "frxExportRTF"
#pragma link "frxExportXLS"
#pragma resource "*.dfm"
TMotorControl *MotorControl;

SerialPort  *Comm;
static S8   s_pTxBuff[50];
static U8   s_pRxBuff[50];
static U16  s_RxBuffCnt = 0;
static bool s_WaitRecFlag = false;
static U8   s_Mode = NULL_CMD;
static String s_OldModel;

static TTimer 		*pRunCountTimer;
static TTimer 		*pLostCountTimer;
static TEdit  		*pRunTimeEd;
static TEdit  		*pLostTimeEd;
static TButton 		*pStartBt;
static TADOTable	*pModelADO;

// nhung bien danh cho phan dieu khien motor
static U8   s_Motor1Addr = 1;
static U8   s_Motor2Addr = 2;
static bool s_RunningFlag = false;
static U32  s_TotalStep = 0;
static U32  s_SetStep = 0;
static U32  s_CurFreq = 0;

//---------------------------------------------------------------------------
//chuong trinh lay ve duong dan chuong trinh hoat dong
String GetAppPath(void)
{
    String x,y;
    x = ParamStr(0);
    y = ExtractFileName(ParamStr(0));
	return ( x.SubString(0, x.Length() - y.Length()) );
}

//---------------------------------------------------------------------------
String IncSecond(String iTime)
{
  int hour, minute, second;
  TDateTime time;

  hour 	 = StrToInt( iTime.SubString(1, 2) );
  minute = StrToInt( iTime.SubString(4, 2) );
  second = StrToInt( iTime.SubString(7, 2) );
  if (++second >= 60)
  {
	second = 0;
	if (++minute >= 60)
	{
	  minute = 0;
	  hour++;
	};
  }
  time = EncodeTime(hour, minute, second, 0);
  return ( FormatDateTime("hh:mm:ss", time) );
}

//---------------------------------------------------------------------------
void ClearRxBuffer(void)
{
    s_RxBuffCnt = 0;
    s_WaitRecFlag = true;
}

//---------------------------------------------------------------------------
bool CommSend(U8 iOp, U8* iBuff, U16 iLen)
{
    U16 crc;
    if(Comm->Connected())
    {
        cStr::Copy(s_pTxBuff, iBuff, iLen);
        crc = cStr::GetChecksum(s_pTxBuff, iLen);
        s_pTxBuff[iLen]     = (U8)(crc);
        s_pTxBuff[iLen + 1] = (U8)(crc>>8);
        Comm->SubmitCmd(iOp, s_pTxBuff, iLen+2);
        return (true);
    }
    ShowMessage("Chua mo duoc cong com");
    return (false);
}

//---------------------------------------------------------------------------
void SetFrequency(U32 iFreq)
{
    U8 pBuff[32];

    pBuff[0] = s_Motor1Addr;
    pBuff[1] = MOTOR_WRITE_1REG_CMD;
    pBuff[2] = 0x00;
    pBuff[3] = 0x01;
	U16 temp = iFreq % 600;
    pBuff[4] = (U8)(temp>>8);
    pBuff[5] = (U8)(temp);
    CommSend(SET_SPEED_MOTOR1_CMD, pBuff, 6);

    pBuff[0] = s_Motor2Addr;
    pBuff[1] = MOTOR_WRITE_1REG_CMD;
    pBuff[2] = 0x00;
    pBuff[3] = 0x01;
	temp = iFreq % 600;
    pBuff[4] = (U8)(temp>>8);
    pBuff[5] = (U8)(temp);
    CommSend(SET_SPEED_MOTOR2_CMD, pBuff, 6);
}

//---------------------------------------------------------------------------
void SendStartCmd(void)
{
	U8 pBuff[32];

	pBuff[0] = s_Motor1Addr;
	pBuff[1] = MOTOR_WRITE_1COIL_CMD;
	pBuff[2] = 0x00;
	pBuff[3] = 0x00;
	pBuff[4] = 0xFF;
	pBuff[5] = 0x00;
	CommSend(TURN_OFF_MOTOR1_CMD, pBuff, 6);

	pBuff[0] = s_Motor2Addr;
	pBuff[1] = MOTOR_WRITE_1COIL_CMD;
	pBuff[2] = 0x00;
	pBuff[3] = 0x00;
	pBuff[4] = 0xFF;
	pBuff[5] = 0x00;
	CommSend(TURN_OFF_MOTOR2_CMD, pBuff, 6);
}

//---------------------------------------------------------------------------
void SendStopCmd(void)
{
	U8 pBuff[32];

	pBuff[0] = s_Motor1Addr;
	pBuff[1] = MOTOR_WRITE_1COIL_CMD;
	pBuff[2] = 0x00;
	pBuff[3] = 0x00;
	pBuff[4] = 0x00;
	pBuff[5] = 0x00;
	CommSend(TURN_ON_MOTOR1_CMD, pBuff, 6);

	pBuff[0] = s_Motor2Addr;
	pBuff[1] = MOTOR_WRITE_1COIL_CMD;
	pBuff[2] = 0x00;
	pBuff[3] = 0x00;
	pBuff[4] = 0x00;
	pBuff[5] = 0x00;
	CommSend(TURN_ON_MOTOR2_CMD, pBuff, 6);
}

//---------------------------------------------------------------------------
void RunLine(void)
{
	if (true == s_RunningFlag) return;

	s_CurFreq = 80;
	SetFrequency(s_CurFreq);
	SendStartCmd();
	s_RunningFlag = true;
}

//---------------------------------------------------------------------------
void StopLine(void)
{
    SendStopCmd();
	s_RunningFlag = false;
}
//---------------------------------------------------------------------------
void SerialHandleOnReadEvent(S32 NumBytesIn, U8 *BytesArrived)
{

}

//---------------------------------------------------------------------------
void SetSampleTimer(U16 iTimer)
{
    U8  buff[4];

    buff[0] = ENCODER_ADDRESS;
    buff[1] = SET_SAMPLE_TIMER;
    buff[2] = (U8)(iTimer >> 8);
    buff[3] = (U8)(iTimer);
    CommSend(SET_SAMPLE_TIMER, buff, 4);
}

//---------------------------------------------------------------------------
void SaveModel(String iModel)
{
	if (0 == pModelADO->RecordCount) return;

	String modelBk 	= pModelADO->FieldValues["Model"];

	TLocateOptions searchOption;
	searchOption.Clear();
	if (false == pModelADO->Locate("Model", iModel, searchOption)) return;

	pModelADO->Edit();
	pModelADO->FieldValues["RunTime"] = pRunTimeEd->Text;
	pModelADO->FieldValues["LostTime"] = pLostTimeEd->Text;
	pModelADO->FieldValues["DateTime"] = FormatDateTime("DD/MM/YYYY", Now());
	pModelADO->Post();

	pModelADO->Locate("Model", modelBk, searchOption);
}

//---------------------------------------------------------------------------
void Run(void)
{
	pRunCountTimer->Enabled = true;
	pLostCountTimer->Enabled	= false;
	pRunTimeEd->Font->Color = clBlue;
	pLostTimeEd->Font->Color = clWindowText;

	RunLine();
	pStartBt->Caption = "PAUSE";
}

//---------------------------------------------------------------------------
void Pause(void)
{
	pRunCountTimer->Enabled = false;
	pLostCountTimer->Enabled	= true;
	pRunTimeEd->Font->Color = clWindowText;
	pLostTimeEd->Font->Color = clRed;

	StopLine();
	pStartBt->Caption = "START";
}

//---------------------------------------------------------------------------
void Stop(void)
{
	pRunCountTimer->Enabled = false;
	pLostCountTimer->Enabled	= false;
	pRunTimeEd->Font->Color = clWindowText;
	pLostTimeEd->Font->Color = clWindowText;

	StopLine();
	pStartBt->Caption = "START";
}

//---------------------------------------------------------------------------
void ReceiveHandle (cCommCommand* pCmd)
{
    U8* pBuff = pCmd->m_Data.Buff;
    switch (pCmd->m_Data.Operation)
    {
    case GET_STATUS_CMD:
        {
            if (cCommCommand::RECEIVE_DONE == pCmd->m_Data.Status)
            {
                if (pBuff[0] == ENCODER_ADDRESS && pBuff[1] == GET_STATUS_CMD)
                {
					if ( ON_STATUS == (pBuff[2] & ON_STATUS) )
                    {
						Run();
						SaveModel(s_OldModel);
					}
                    if ( OFF_STATUS == (pBuff[2] & OFF_STATUS) )
					{
						Pause();
						SaveModel(s_OldModel);
					}
                    U32 curStep = pBuff[3] * 0x1000000 + pBuff[4] * 0x10000 + pBuff[5] * 0x100 + pBuff[6];
                    s_TotalStep += curStep;
                    if (true == s_RunningFlag)
                    {
                        if ( curStep > (s_SetStep + DIFF_STEP) )
                        {
                            s_CurFreq -= FREQ_INC;
                            SetFrequency(s_CurFreq);
                        }
                        else if ( curStep < s_SetStep - DIFF_STEP )
                        {
                            s_CurFreq += FREQ_INC;
                            SetFrequency(s_CurFreq);
                        }
                    }
                }
            }
			else if (cCommCommand::RECEIVE_TIMEOUT == pCmd->m_Data.Status)
            {

            }


        } break;

    case SET_SAMPLE_TIMER:
        {
            if ( pBuff[0] == ENCODER_ADDRESS && pBuff[1] == SET_SAMPLE_TIMER )
            {
                if (cCommCommand::RECEIVE_DONE == pCmd->m_Data.Status)
                {
                    int temp = pBuff[2] * 0x100 + pBuff[3];

                }
                else if ( cCommCommand::RECEIVE_TIMEOUT == pCmd->m_Data.Status )
                {

                }
            }
        } break;
    }
}


//---------------------------------------------------------------------------
void __fastcall TMotorControl::InsertRecord(String iModel, String iTarget, String iOT, String iRunTime, String iStopTime, String iDate)
{
	ModelADO->Insert();
	ModelADO->FieldByName("Model")->AsString = iModel;
	ModelADO->FieldByName("Target")->AsString = iTarget;
	ModelADO->FieldByName("OT")->AsString = iOT;
	ModelADO->FieldByName("RunTime")->AsString = iRunTime;
	ModelADO->FieldByName("LostTime")->AsString = iStopTime;
	ModelADO->FieldByName("DateTime")->AsString = iDate;
	ModelADO->Post();
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::GetModelItem(void)
{
	if ( ModelADO->RecordCount > 0 )
	{
		String oldModel = ModelADO->FieldValues["Model"];
		ModelCb->Items->Clear();
		ModelADO->First();

		String s;
		for (int i= 0; i<ModelADO->RecordCount; i++)
		{
			s = ModelADO->FieldValues["Model"];
			ModelCb->Items->Add(s);
			if (i < ModelADO->RecordCount - 1) { ModelADO->Next(); }
		}

		TLocateOptions searchOption;
		searchOption.Clear();
		ModelADO->Locate("Model", oldModel, searchOption);
	}
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::LoadModel(void)
{
	String model 	= ModelADO->FieldValues["Model"];
	String target 	= ModelADO->FieldValues["Target"];
	String ot 		= ModelADO->FieldValues["OT"];
	String runTime 	= ModelADO->FieldValues["RunTime"];
	String lostTime = ModelADO->FieldValues["LostTime"];

	ModelCb->Text 		= model;
	TargetEd->Text 		= target;
	RunTimeEd->Text		= runTime;
	LostTimeEd->Text	= lostTime;

	U32 timeWork = TIME_WORK;
	if ( (ot == "Yes") || (ot == "yes") || (ot == "Y") || (ot == "y") )
	{
		timeWork += TIME_OT;
		OverTimeLb->Caption = "Yes ==> Work time in day: " + IntToStr((int)timeWork) + " minutes";
		OverTimeLb->Font->Color = clRed;
	}
	else
	{
		OverTimeLb->Caption = "No ==> Work time in day: " + IntToStr((int)timeWork) + " minutes";
		OverTimeLb->Font->Color = clBlue;
	}

	U32 targetInt = (U32)StrToInt(target);
	StandardSpeedEd->Text = IntToStr( (int)( (timeWork * 60) / targetInt ) );
	ActualSpeedEd->Text = IntToStr( (int)( (timeWork * 60 * EFFICIENCY) / (targetInt * 100) ) );

	SpeedCtrl->Position = (int)( (targetInt * 100 * 1120) / (timeWork * 60 * EFFICIENCY) );
	s_OldModel = model;
}

//---------------------------------------------------------------------------
__fastcall TMotorControl::TMotorControl(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TMotorControl::FormCreate(TObject *Sender)
{
    Comm = new SerialPort(false);
    Sleep(50);
    Comm->SetupRxCallback(&SerialHandleOnReadEvent);
	Comm->SetupSubmitStatusCallback(&ReceiveHandle);
    Comm->BaudRate      = 9600;
	Comm->PortNumber    = COM1;
    Comm->Parity        = PAR_NONE;
	Comm->Open();

	pPassADO 		= PassADO;
	pModelADO 		= ModelADO;
    pRunCountTimer 	= RunCountTimer;
	pLostCountTimer = LostCountTimer;
    pRunTimeEd 		= RunTimeEd;
	pLostTimeEd 	= LostTimeEd;
	pStartBt 		= StartBt;


	SettingGroupGird->Height = PageCtrl->Height - SettingGroupBt->Height - 50;

	if ( 0 < ModelADO->RecordCount )
	{
		ModelADO->First();
		LoadModel();
		GetModelItem();
	}
	else
	{
		SpeedCtrl->Position = 0;
    }
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::SendClick(TObject *Sender)
{
    PollingTimer->Interval = 3000;
    SetSampleTimer(PollingTimer->Interval);
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::PollingTimerTimer(TObject *Sender)
{
	U8  buff[4];

	buff[0] = ENCODER_ADDRESS;
    buff[1] = GET_STATUS_CMD;
    CommSend(GET_STATUS_CMD, buff, 2);
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::FormResize(TObject *Sender)
{
	 SettingGroupGird->Height = PageCtrl->Height - SettingGroupBt->Height - 50;
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::SpeedCtrlChange(TObject *Sender)
{
	s_SetStep = SpeedCtrl->Position;
	if ( 0 < s_SetStep )
	{
		AdjTargetLb->Caption = "Speed = " + IntToStr((int)s_SetStep) + " mm/s";
	}
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::TargetAdjBtClick(TObject *Sender)
{
    s_AdjEnable = true;
    PassForm->Show();
    MotorControl->Enabled = false;
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::SpeedCtrlExit(TObject *Sender)
{
	SpeedCtrl->Enabled = false;
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::PageCtrlChange(TObject *Sender)
{
    if (PageCtrl->ActivePageIndex == 1)
    {
        s_AdjEnable = false;
        PassForm->Show();
		MotorControl->Enabled = false;
	}
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::NewBtClick(TObject *Sender)
{
	int i = 0;
	String s;
	TLocateOptions searchOption;
	searchOption.Clear();
	do
	{
		i++;
		s = "Model"+IntToStr(i);
	}
	while (ModelADO->Locate("Model", s, searchOption) == true);

	TDateTime myDateTime = Now();
	String dateStr = FormatDateTime("DD/MM/YYYY", myDateTime);
	myDateTime = EncodeTime(00, 00, 00, 000);
	String timeStr = FormatDateTime("hh:mm:ss", myDateTime);
	InsertRecord( s, "700", "No", timeStr, timeStr, dateStr );
	GetModelItem();
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::StartBtClick(TObject *Sender)
{
	if ( "START" == StartBt->Caption )
	{
		Run();
		SaveModel(s_OldModel);
	}
	else
	{
		Pause();
		SaveModel(s_OldModel);
	}
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::StopBtClick(TObject *Sender)
{
	Stop();
	SaveModel(s_OldModel);
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::DeleteBtClick(TObject *Sender)
{
	if ( 0 == ModelADO->RecordCount ) return;
	ModelADO->Delete();

	TLocateOptions searchOption;
	searchOption.Clear();
	if ( false == ModelADO->Locate("Model", ModelCb->Text, searchOption) )
	{
		Pause();
		LoadModel();
	}

	if ( 0 == ModelADO->RecordCount )
	{
        NewBtClick(Sender);
	}
	GetModelItem();
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::ChangePassBtClick(TObject *Sender)
{
	ChangePassword->Show();
    MotorControl->Enabled = false;
}


void __fastcall TMotorControl::ActiveBtClick(TObject *Sender)
{
	Stop();
	SaveModel(s_OldModel);
	LoadModel();
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::ModelCbChange(TObject *Sender)
{
	TLocateOptions searchOption;
	searchOption.Clear();
	if (true == ModelADO->Locate("Model", ModelCb->Text, searchOption))
	{
		Stop();
		SaveModel(s_OldModel);
		LoadModel();
	}
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::RunCountTimerTimer(TObject *Sender)
{
	String s = IncSecond(RunTimeEd->Text);
	RunTimeEd->Text = s;
}

//---------------------------------------------------------------------------
void __fastcall TMotorControl::LostCountTimerTimer(TObject *Sender)
{
	LostTimeEd->Text = IncSecond(LostTimeEd->Text);
}

//---------------------------------------------------------------------------

void __fastcall TMotorControl::ReportBtClick(TObject *Sender)
{
	frReport->ShowReport(true);
}

//---------------------------------------------------------------------------
